FlutterでGoogle Mapを表示してみた
大阪オフィスの山田です。前回から引き続いて、楽しくFlutterいじりしているこの頃です。今回はGoogle Mapを表示してみようと思います。
開発環境
flutter doctor
の結果です。
Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel beta, v0.5.1, on Mac OS X 10.13.5 17F77, locale ja-JP) [✓] Android toolchain - develop for Android devices (Android SDK 28.0.1) [✓] iOS toolchain - develop for iOS devices (Xcode 9.3) [✓] Android Studio (version 3.1) ✗ Flutter plugin not installed; this adds Flutter specific functionality. ✗ Dart plugin not installed; this adds Dart specific functionality. [!] VS Code (version 1.25.1) [✓] Connected devices (2 available)
VSCodeの警告が出ていますが、Extensionインストール済みです。
Flutterのバージョンは以下の通りです。
Flutter 0.5.1 • channel beta • https://github.com/flutter/flutter.git Framework • revision c7ea3ca377 (2 months ago) • 2018-05-29 21:07:33 +0200 Engine • revision 1ed25ca7b7 Tools • Dart 2.0.0-dev.58.0.flutter-f981f09760
この次ぐらいにはFlutterをバージョンアップしよう。
作る画面
本当に地図を表示して閉じるだけの画面です。
必要な準備
以下の準備が必要です。
map_viewパッケージを入れる
map_viewというパッケージを入れます。
2018/08/09時点で最新バージョンの0.0.14
を入れます。pubspec.yaml
のdependenciesに以下の行を追加します。
map_view: ^0.0.14
VSCodeを使っていると、pubspec.yaml
を更新したら自動で取得してくれますね。便利。自動で取得できない場合は、flutter packages get
コマンドを打ちましょう。
Google MapのAPIキーを作成する
こちらのページにて作成します。 以下の二つのAPIを有効にします。
有効にしたら認証情報を作成し、APIキーを入手しましょう。これでGoogle Mapを利用する準備が整いました。
iOSでパーミッション設定をする
ios/Runner/Info.plist
を編集します。Xcodeでプロジェクトを開いて編集しました。以下の記述を追加します。
<key>NSLocationWhenInUseUsageDescription</key> <string>Using location to display on a map</string>
Androidでパーミッション設定をする
1 android/app/src/main
配下にあるAndroidManifest.xml
に以下の記述を追加します。
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
2 続いて同ファイルのapplication
タグの内側に以下の記述を追加します。your_api_key
には、作成したAPIキーを設定してください。
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="your_api_key"/> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/>
3 続いて同ファイルに以下の記述を追加します。
<activity android:name="com.apptreesoftware.mapview.MapActivity" android:theme="@style/Theme.AppCompat.Light.DarkActionBar"/>
4 android/build.gradle
ファイルのbuildScript
-> dependencies
の中に以下の記述を追加します。
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.2-4'
※KotlinでProjectを作っていたことが原因かわかりませんが、私の環境ではすでにkotlin-gradle-pluginの記述があったので、手順4については省略しました。
実装
まず、APIキーを設定します。今回はmainメソッドの中で設定しました。
void main() { MapView.setApiKey("your_api_key"); runApp(new MyApp()); }
次に、地図を表示するボタンを配置します。ボタンがタップされたのを検知し、後述する_showMap
メソッドをコールします。
var _mapView = MapView(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Map"), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ RaisedButton( child: Text('Show Map modal.'), onPressed: () { _showMap(); }, ), ], ), ), ); }
次は、いよいよ地図を表示します。モーダルで表示されます。
void _showMap() { _mapView.show(new MapOptions( showUserLocation: true, hideToolbar: false, showMyLocationButton: true, showCompassButton: true, ), toolbarActions: [new ToolbarAction("Close", 1)] ); _mapView.onToolbarAction.listen((id) { if (id == 1) { _mapView.dismiss(); } }); }
表示するときにはMapOptionsを指定して表示します。現在地へ移動するボタンやコンパスボタンを表示するよ、などの設定を入れています。見たまんまですね。onToolbarAction
をlistenすることで、タップされたらmapViewを閉じてます。
おまけ
開いた時、現在地
を中心に地図が表示されてほしい。
こんな感じに。
すんなりいくのかなと思いきや、ちょっとハマりました。探すと似たような内容がGithubのIssueに上がっているのですが、読んだ結果...
(´・ω・`)???
だったので、なんとなくこういう風にしたら実現できたという(ちょっと無理矢理ですが)実装を載せておきます。
Location userLocation; // _showMapメソッドの最後に以下の処理を追加 _mapView.onMapReady.listen((_) { if (userLocation != null) { _mapView.setCameraPosition( new CameraPosition(new Location(userLocation.latitude, userLocation.longitude), 14.0) ); } }); _mapView.onLocationUpdated.listen((location) { if (userLocation == null) { userLocation = location; _mapView.setCameraPosition( new CameraPosition(new Location(userLocation.latitude, userLocation.longitude), 14.0) ); } });
Locationが更新?されたタイミングでLocationを覚えておきます。初めて取得する場合は、mapのカメラポジションも移動させます。2回目開いた時はそのままそのポジションを使います。うーん。。。なんかもうちょい良い方法考えた方が良さそうですが、一旦ここまで。
最後に
如何だったでしょうか。Flutterいじりは楽しいのでこれからもちょくちょくブログを書くと思います。